package service

import (
	"gitee.com/man0sions/go-cron/common"
	"log"
	"time"
)

type Scheduler struct {
	jobChan    chan *common.Job
	runningJob map[string]*common.Job //正在运行中的job
	resultChan chan *common.ExecResult
}

var (
	Gscheduler *Scheduler
)

func (sch *Scheduler) AddTask(job *common.Job) {
	sch.jobChan <- job
}

func (sch *Scheduler) AddResult(ret *common.ExecResult) {
	sch.resultChan <- ret
}
func (sch *Scheduler) handleJob(job *common.Job) {

	switch job.Type {
	case common.JOB_TYPE_PUT:
		sch.runningJob[job.Name] = job
	case common.JOB_TYPE_DEL:
		_, ok := sch.runningJob[job.Name]
		if ok {
			delete(sch.runningJob, job.Name)
		}
	case common.JOB_TYPE_KILL:
		plan, ok := sch.runningJob[job.Name]
		if !ok {
			common.Warn(nil, "plan error")
			return
		}
		log.Println("cancel")
		plan.Cancel()

	}
}

func (sch *Scheduler) runJob() (after time.Duration) {

	var (
		err error
	)
	var (
		nearTime *time.Time
	)
	if len(sch.runningJob) == 0 {
		return time.Second * 1
	}
	now := time.Now()
	for _, job := range sch.runningJob {

		if job.NextTime.Before(now) || job.NextTime.Equal(now) {
			//run
			if err = common.BuildJobPlan(job); err != nil {
				common.Warn(nil, err)
			}
			GExecJob.Run(job)
			//log.Println("run", plan)
			job.NextTime = job.Expr.Next(time.Now())
		}
		if nearTime == nil || job.NextTime.Before(*nearTime) {
			nearTime = &job.NextTime
		}
	}
	after = (*nearTime).Sub(time.Now())
	return
}
func (sch *Scheduler) LoopJobs() (err error) {
	after := sch.runJob() //计算下次调度时间
	tc := time.NewTimer(after)
	for {
		select {
		case job := <-sch.jobChan:
			sch.handleJob(job)

		case <-tc.C:
		case ret := <-sch.resultChan:
			sch.handleResult(ret)
		}
		after = sch.runJob() //计算下次调度时间
		tc.Reset(after)
	}
}
func (sch *Scheduler) handleResult(ret *common.ExecResult) {
	ip, _ := common.GetIp()
	if ret.Err != common.ERR_LOCKED {
		msg := ""
		if ret.Err != nil {
			msg = ret.Err.Error()

		}
		wlog := &common.JobLog{
			JobName:      ret.Job.Name,
			Command:      ret.Job.Command,
			Err:          msg,
			Output:       ip + " , "+string(ret.Output),
			PlanTime:     0,
			ScheduleTime: 0,
			StartTime:    ret.StartTime.UnixNano() / 1000 / 1000,
			EndTime:      ret.EndTime.UnixNano() / 1000 / 1000,
		}
		log.Printf("%+v",wlog)
		common.GBatchLog.AddLog(wlog)

	}
}
func InitScheduler() (err error) {
	Gscheduler = &Scheduler{
		jobChan:    make(chan *common.Job, 1024),
		runningJob: make(map[string]*common.Job),
		resultChan: make(chan *common.ExecResult, 1024),
	}
	InitExecJob()
	go Gscheduler.LoopJobs()
	return
}
